﻿using System;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.PolicyInjection.Configuration;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;

namespace SGRapidForm.Extensions
{
    internal class PolicyInjectionHelper : IDisposable
    {
        public IUnityContainer Container
        { get; private set; }

        private static readonly TransparentProxyInterceptor injector = new TransparentProxyInterceptor();

        public PolicyInjectionHelper(IConfigurationSource configurationSource, IUnityContainer container)
        {
            if (container == null)
            {
                throw new ArgumentNullException("container");
            }

            this.Container = container;
            this.Container.AddNewExtension<Interception>();
            PolicyInjectionSettings section = (PolicyInjectionSettings)configurationSource.GetSection("policyInjection");
            if (section != null)
            {
                section.ConfigureContainer(this.Container, configurationSource);
            }
        }

        public TInterface Create<TObject, TInterface>(params object[] args)
        {
            return (TInterface)this.Create(typeof(TObject), typeof(TInterface), args);
        }

        public TObject Create<TObject>(params object[] args)
        {
            return (TObject)this.Create(typeof(TObject), typeof(TObject), args);
        }

        public object Create(Type typeToCreate, params object[] args)
        {
            return this.Create(typeToCreate, typeToCreate, args);
        }

        public object Create(Type typeToCreate, Type typeToReturn, params object[] args)
        {
            return this.DoCreate(typeToCreate, typeToReturn, args);
        }

        private object DoCreate(Type typeToCreate, Type typeToReturn, object[] arguments)
        {
            object instance = Activator.CreateInstance(typeToCreate, arguments);
            return this.DoWrap(instance, typeToReturn);
        }

        private object DoWrap(object instance, Type typeToReturn)
        {
            this.Container.Configure<Interception>().SetDefaultInterceptorFor(typeToReturn, injector);
            return this.Container.BuildUp(typeToReturn, instance);
        }

        void IDisposable.Dispose()
        {
            if (this.Container != null)
            {
                this.Container.Dispose();
            }
        }

        public TInterface Wrap<TInterface>(object instance)
        {
            return (TInterface)this.Wrap(instance, typeof(TInterface));
        }

        public object Wrap(object instance, Type typeToReturn)
        {
            return this.DoWrap(instance, typeToReturn);
        }
    }
}
